#include <iostream>
#include <functional>
#include <vector>
#include <unistd.h>
#include <memory>
#include <unordered_map>

using OnCloseTime = std::function<void()>; //定时器要执行的任务
using ReleaseTime = std::function<void()>; //删除时间管理对象中weak_ptr的信息

//定时器任务对象
class TimeTask
{
private:
    uint32_t _timeout; //超时时间
    uint64_t _id; //每个任务的id
    bool _cancel; //取消定时任务
    OnCloseTime _close_cb; //销毁定时任务的回调
    ReleaseTime _release_cb; //因为时间轮中会记录一个weak_ptr对象，所以最后需要销毁
public:
    TimeTask(uint32_t timeout,uint64_t id,const OnCloseTime& close_cb):_timeout(timeout),_id(id),_close_cb(close_cb),_cancel(false){}
    ~TimeTask(){ 
        if(_cancel== false) _close_cb();
        _release_cb();
    }
    uint64_t id() { return _id; }
    void SetRelease(const ReleaseTime& release_cb) { _release_cb = release_cb; }
    uint32_t Delay() { return _timeout; }
    void Cancel() { _cancel = true; }
};

//时间轮管理对象
class TimeWheel
{
private:
    using WeakTask = std::weak_ptr<TimeTask>; //使用weak_ptr防止在shared_ptr直接对对象的操作
    using PtrTask = std::shared_ptr<TimeTask>; //使用shared_ptr保证释放时不到0不销毁
    int _capacity; //记录时间轮的大小
    int _tick; //记录当前指针指向的时间，指到哪里，销毁哪里
    std::vector<std::vector<PtrTask>> _wheel; //时间轮
    std::unordered_map<uint64_t,WeakTask> _times; //记录id和weak_ptr之间的映射关系
private:
    void RemoveTask(uint64_t id)
    {
        if(_times.find(id) != _times.end())
        {
            _times.erase(id);
        }
    }
public:
    TimeWheel():_tick(0),_capacity(60),_wheel(_capacity){}
    void AddTask(uint64_t id,uint32_t delay,const OnCloseTime close_cb)
    {
        PtrTask pt(new TimeTask(delay,id,close_cb));
        //设置ReleaseTask
        pt->SetRelease(std::bind(&TimeWheel::RemoveTask,this,id));
        //把任务添加到数组中
        int pos = (_tick + delay) %_capacity;
        _wheel[pos].push_back(pt);
        //将id和weakTask映射关联起来
        _times[id] = WeakTask(pt);
    }
    void CancelTask(uint64_t id)
    {
        //通过id找到任务，如果没有直接返回，有的话将标志置为true
        if(_times.find(id) == _times.end()) return;
        PtrTask pt = _times[id].lock(); //获得weak_ptr中的shared_ptr
        pt->Cancel();
    }
    void RefreshTask(uint64_t id)
    {
        //创建一个新的智能指针对象，然后添加到数组中
        //如果在原数组中没有找到，那么直接返回
        if(_times.find(id) == _times.end()) return;
        std::cout<<"找到了定时任务\n";
        PtrTask pt = _times[id].lock(); //获得weak_ptr中的shared_ptr
        int delay = pt->Delay();
        int pos = (_tick + delay) %_capacity;
        _wheel[pos].push_back(pt);
    }
    void RunTask()
    {
        _tick = (_tick+1)%_capacity;
        _wheel[_tick].clear();
    }
};

class test
{
public: 
    test() { std::cout<< "构造" <<std::endl; }
    ~test() { std::cout<< "析构" <<std::endl; }
};

void del(test* t)
{
    delete t;
}
int main()
{
    TimeWheel tw;
    test* t = new test();
    tw.AddTask(111,5,std::bind(del,t));
    for(int i = 0;i<5;++i)
    {
        sleep(1);
        tw.RefreshTask(111);
        std::cout<<"过去了1秒，重新刷新任务"<<std::endl;
        tw.RunTask();
    }
    std::cout<<"取消定时任务"<<std::endl;
    tw.CancelTask(111);
    while(1)
    {
        std::cout<<"**********************"<<std::endl;
        sleep(1);
        tw.RunTask();
    }
    return 0;
}